home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 12
/
Mac Magazin and MacEasy Magazine CD - Issue 12.iso
/
Sharewarebibliothek
/
Anwendungen
/
Wissenschaft & Technik
/
Finder Marquee ƒ
/
finder_marquee.c
< prev
next >
Wrap
Text File
|
1995-07-10
|
7KB
|
237 lines
/*
Finder Marquee
by Jordan Zimmerman
(c)1995 by Altura Software, Inc.
Unlimited use is hereby granted without restriction. However,
the author would appreciate credit if possible. Please send
comments, questions, bugs, etc. to jordanz@altura.com
This code implements a "rubber band" marquee select rect
with very smooth drawing in a manner similar to the Mac Finder.
Change History:
1.0.0 07/10/95 JLZ Created inital C version from existing C++ framework
*/
#include "finder_marquee.h"
static void calculate_marquee_r(finder_marquee_rec* marquee_ptr);
static void draw_marquee_r(const finder_marquee_rec* marquee_ptr);
static void make_frame_region(RgnHandle target_rgn_h, const Rect* frame_r_ptr, RgnHandle work_rgn_h);
//-------------Global Functions------------
void FinderMarqueeBegin(finder_marquee_rec* marquee_ptr, Point mouse_down_pt)
{
// save the first mouse as our anchor point
marquee_ptr->pin_pt = mouse_down_pt;
// it's also our current point
marquee_ptr->current_pt = mouse_down_pt;
// make the marquee_r
calculate_marquee_r(marquee_ptr);
// allow selections to draw now to avoid and screen turds
if ( marquee_ptr->change_selection_proc )
{
Rect old_marquee_r = marquee_ptr->marquee_r;
marquee_ptr->change_selection_proc(marquee_ptr, &old_marquee_r);
}
// display the first marquee_r - important to have a balance when FinderMarqueeEnd is called
draw_marquee_r(marquee_ptr);
} // FinderMarqueeBegin
void FinderMarqueeEnd(finder_marquee_rec* marquee_ptr)
{
// remove the marquee from the screen -
// this works because FinderMarqueeBegin drew it
draw_marquee_r(marquee_ptr);
} // FinderMarqueeEnd
void FinderMarqueeContinue(finder_marquee_rec* marquee_ptr, Point new_mouse_pt)
{
PenState pen_state;
Rect old_marquee_r;
RgnHandle old_rgn_h = NULL;
RgnHandle work_rgn_h = NULL;
RgnHandle new_rgn_h = NULL;
RgnHandle clip_rgn_h = NULL;
int success_flag = false;
// avoid flashing step 1 - do nothing if the mouse hasn't moved
if ( EqualPt(new_mouse_pt, marquee_ptr->current_pt) )
{
return;
}
clip_rgn_h = NewRgn();
if ( !clip_rgn_h )
{
return; // can't find 10 bytes! We're probably already in big trouble
}
// we'll be messing with the clip, so save it for later restoration
GetClip(clip_rgn_h);
// save and setup the pen
GetPenState(&pen_state);
PenMode(patXor);
PenPat(&qd.gray);
// save the old marquee_r and setup the new one
old_marquee_r = marquee_ptr->marquee_r;
marquee_ptr->current_pt = new_mouse_pt;
calculate_marquee_r(marquee_ptr);
do
{
old_rgn_h = NewRgn();
if ( !old_rgn_h )
{
break;
}
work_rgn_h = NewRgn();
if ( !work_rgn_h )
{
break;
}
new_rgn_h = NewRgn();
if ( !new_rgn_h )
{
break;
}
// generate 1 pixel thick outline regions of the old and new marquee_r
make_frame_region(old_rgn_h, &old_marquee_r, work_rgn_h);
make_frame_region(new_rgn_h, &marquee_ptr->marquee_r, work_rgn_h);
// get the area in common between the old and the new
SectRgn(old_rgn_h, new_rgn_h, work_rgn_h);
// set the clip to the old clip minus the common area of the old and new marquee rect
DiffRgn(clip_rgn_h, work_rgn_h, work_rgn_h);
SetClip(work_rgn_h);
if ( marquee_ptr->selections_proc && marquee_ptr->selections_proc(marquee_ptr) )
{
// If there is a selection, the old marquee must be erased, the selections must be drawn,
// and then the new marquee can be drawn.
FrameRect(&old_marquee_r);
if ( marquee_ptr->change_selection_proc )
{
marquee_ptr->change_selection_proc(marquee_ptr, &old_marquee_r);
}
FrameRect(&marquee_ptr->marquee_r);
}
else
{
// If there's no selection change, the marquee can be drawn in one step
// that will erase the old and draw the new.
UnionRgn(new_rgn_h, old_rgn_h, work_rgn_h);
PaintRgn(work_rgn_h); // this will both erase the old and draw the new
}
} while ( success_flag++ ); // i.e. do once, set success_flag on exit
if ( !success_flag )
{
// memory is evidently very tight, we'll have to live with flashing
FrameRect(&old_marquee_r);
if ( marquee_ptr->change_selection_proc )
{
marquee_ptr->change_selection_proc(marquee_ptr, &old_marquee_r);
}
FrameRect(&marquee_ptr->marquee_r);
}
// restore clip and pen and then cleanup
SetClip(clip_rgn_h);
SetPenState(&pen_state);
if ( old_rgn_h )
{
DisposeRgn(old_rgn_h);
}
if ( work_rgn_h )
{
DisposeRgn(work_rgn_h);
}
if ( new_rgn_h )
{
DisposeRgn(new_rgn_h);
}
if ( clip_rgn_h )
{
DisposeRgn(clip_rgn_h);
}
} // FinderMarqueeContinue
//-------------Local Functions-------------
// calculating the marquee rect isn't as simple as Pt2Rect. Using Pt2Rect
// causes the pin point to shift around. This function will calculate a
// correct marquee rect that keeps the pin point in place
static void calculate_marquee_r(finder_marquee_rec* marquee_ptr)
{
if ( (marquee_ptr->current_pt.h >= marquee_ptr->pin_pt.h) && (marquee_ptr->current_pt.v >= marquee_ptr->pin_pt.v) ) // Quadrant IV
{
SetRect(&marquee_ptr->marquee_r, marquee_ptr->pin_pt.h, marquee_ptr->pin_pt.v, marquee_ptr->current_pt.h + 1, marquee_ptr->current_pt.v + 1);
}
else if ( (marquee_ptr->current_pt.h <= marquee_ptr->pin_pt.h) && (marquee_ptr->current_pt.v <= marquee_ptr->pin_pt.v) ) // Quadrant I
{
SetRect(&marquee_ptr->marquee_r, marquee_ptr->current_pt.h, marquee_ptr->current_pt.v, marquee_ptr->pin_pt.h + 1, marquee_ptr->pin_pt.v + 1);
}
else if ( (marquee_ptr->current_pt.h >= marquee_ptr->pin_pt.h) && (marquee_ptr->current_pt.v <= marquee_ptr->pin_pt.v) ) // Quadrant II
{
SetRect(&marquee_ptr->marquee_r, marquee_ptr->pin_pt.h, marquee_ptr->current_pt.v, marquee_ptr->current_pt.h + 1, marquee_ptr->pin_pt.v + 1);
}
else // Quadrant III
{
SetRect(&marquee_ptr->marquee_r, marquee_ptr->current_pt.h, marquee_ptr->pin_pt.v, marquee_ptr->pin_pt.h + 1, marquee_ptr->current_pt.v + 1);
}
} // calculate_marquee_r
// outline the marquee rect in Xor gray
static void draw_marquee_r(const finder_marquee_rec* marquee_ptr)
{
PenState pen_state;
GetPenState(&pen_state);
PenMode(patXor);
PenPat(&qd.gray);
FrameRect(&marquee_ptr->marquee_r);
SetPenState(&pen_state);
} // draw_marquee_r
// utility to make a 1 pixel thick region of the frame outline of a rect
static void make_frame_region(RgnHandle target_rgn_h, const Rect* frame_r_ptr, RgnHandle work_rgn_h)
{
RectRgn(target_rgn_h, frame_r_ptr);
CopyRgn(target_rgn_h, work_rgn_h);
InsetRgn(work_rgn_h, 1, 1);
DiffRgn(target_rgn_h, work_rgn_h, target_rgn_h);
} // make_frame_region